/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pig.mt.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.common.core.exception.CheckedException;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.mt.config.WxMaConfiguration;
import com.pig4cloud.pig.mt.entity.User;
import com.pig4cloud.pig.mt.entity.WxInfo;
import com.pig4cloud.pig.mt.mapper.WxInfoMapper;
import com.pig4cloud.pig.mt.service.UserService;
import com.pig4cloud.pig.mt.service.WxInfoService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 *
 * @author JLM
 * @date 2021-03-05 11:45:08
 */
@Slf4j
@Service
public class WxInfoServiceImpl extends ServiceImpl<WxInfoMapper, WxInfo> implements WxInfoService {
	@Autowired
	private WxMpService wxService;
	@Autowired
	private UserService userService;
//	@Autowired
//	private SysUserTokenService sysUserTokenService;
//    @Autowired
//    private ApiRedisUtils apiRedisUtils;

	@Override
	public R<?> appLoginByCode(String appid, String code) {
		try {
			if (!this.wxService.switchover(appid)) {
				throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
			}
			//通过第一步获得的code获取微信授权信息
			WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
			if (accessToken == null || StringUtils.isBlank(accessToken.getOpenId())) {
				throw new CheckedException("微信授权失败");
			}
			String unionId = accessToken.getUnionId();
			if (unionId == null || accessToken.getAccessToken() == null) {
				throw new CheckedException("微信登录失败");
			}
			//根据openid查询时候有用户信息
			WxInfo wxInfo = getOne(Wrappers.<WxInfo>lambdaQuery()
					.eq(WxInfo::getAppAppid, accessToken.getOpenId())
					.or(a->a.eq(WxInfo::getWxUnionId, unionId)));
			if (wxInfo != null) {
				String uid = wxInfo.getUserId();
				String appAppid = wxInfo.getAppAppid();
				if (uid != null) {
					if (StringUtils.isEmpty(appAppid)) {
						wxInfo.setAppAppid(accessToken.getOpenId());
						updateById(wxInfo);
					}
					User user = userService.getById(uid);
					if (user != null) {
						//已经绑定用户信息直接登录
//						return sysUserTokenService.createUserToken(sysUserEntity.getUserId(), LoginConstant.FROM_ANDROID);
					}
				}
			}
			Map<String, Object> res = new HashMap<>();
			res.put("wxtoken", accessToken.getAccessToken());
			res.put("wxOpenId", accessToken.getOpenId());
			res.put("bindPhone", true);
			//没有绑定用户请前往绑定
			return R.ok(res);
		} catch (Exception e) {
			throw new CheckedException("微信登录失败:" + e.getMessage());
		}
	}

	@Override
	public WxOAuth2UserInfo getWxUserInfo(String appid, String code) {
		try {
			if (!wxService.switchover(appid)) {
				throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
			}
			//通过第一步获得的code获取微信授权信息
			WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
			if (accessToken == null || StringUtils.isBlank(accessToken.getOpenId())) {
				throw new CheckedException("微信授权失败");
			}
			String unionId = accessToken.getUnionId();
			if (unionId == null || accessToken.getAccessToken() == null) {
				throw new CheckedException("微信登录失败");
			}
			WxOAuth2UserInfo userInfo = wxService.getOAuth2Service().getUserInfo(accessToken, "zh_CN");
			return userInfo;
		} catch (Exception e) {
			throw new CheckedException("微信登录失败:" + e.getMessage());
		}
	}

	@Override
	public WxOAuth2UserInfo getWxUserInfoByAk(String appid, String openId, String wxAk) {
		try {
			if (!this.wxService.switchover(appid)) {
				throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
			}
			WxOAuth2AccessToken accessToken = new WxOAuth2AccessToken();
			accessToken.setAccessToken(wxAk);
			accessToken.setOpenId(openId);
			WxOAuth2UserInfo userInfo = wxService.getOAuth2Service().getUserInfo(accessToken, "zh_CN");
			return userInfo;
		} catch (Exception e) {
			throw new CheckedException("登录失败:" + e.getMessage());
		}
	}

	@Override
	public void bindAppAppid(String userId, WxOAuth2UserInfo userInfo) {
		WxInfo wxInfoEntity = getOne(Wrappers.<WxInfo>lambdaQuery()
				.eq(WxInfo::getWxUnionId, userInfo.getUnionId()));
		if (wxInfoEntity == null) {
			wxInfoEntity = new WxInfo();
			wxInfoEntity.setUserId(userId);
			wxInfoEntity.setWxUnionId(userInfo.getUnionId());
			wxInfoEntity.setAppAppid(userInfo.getOpenid());

			wxInfoEntity.setNickName(userInfo.getNickname());
			wxInfoEntity.setCity(userInfo.getCountry()+"-"
					+userInfo.getProvince()+"-"
					+userInfo.getCity());
			wxInfoEntity.setAvatarUrl(userInfo.getHeadImgUrl());
			wxInfoEntity.setSex(userInfo.getSex());
			save(wxInfoEntity);
		} else {
			wxInfoEntity.setUserId(userId);
			wxInfoEntity.setAppAppid(userInfo.getOpenid());

			wxInfoEntity.setNickName(userInfo.getNickname());
			wxInfoEntity.setCity(userInfo.getCountry()+"-"
					+userInfo.getProvince()+"-"
					+userInfo.getCity());
			wxInfoEntity.setAvatarUrl(userInfo.getHeadImgUrl());
			wxInfoEntity.setSex(userInfo.getSex());
			updateById(wxInfoEntity);
		}
	}

	@Override
	public void unbindAppAppid(Long userId) {
//        wxInfo wxinfo = getOne(Wrappers.<wxInfo>lambdaQuery()
//                .eq(wxInfo::getUserId, userId));
//        if (wxinfo != null) {
//            wxinfo.setAppAppid(null);
//            wxinfo.setUserId(null);
//            updateById(wxinfo);
//        }
		update(Wrappers.<WxInfo>lambdaUpdate()
				.set(WxInfo::getAppAppid, null)
				.set(WxInfo::getUserId, null)
				.eq(WxInfo::getUserId, userId));
	}

	@Override
	public void bindMpAppid(WxMpUser userWxInfo) {
		if (StringUtils.isEmpty(userWxInfo.getUnionId())) {
			return;
		}
		WxInfo wxInfoEntity = getOne(Wrappers.<WxInfo>lambdaQuery()
				.eq(WxInfo::getWxUnionId, userWxInfo.getUnionId()));
		if (wxInfoEntity == null) {
			wxInfoEntity = new WxInfo();
			wxInfoEntity.setWxUnionId(userWxInfo.getUnionId());
			wxInfoEntity.setMpAppid(userWxInfo.getOpenId());

			wxInfoEntity.setNickName(userWxInfo.getNickname());
			wxInfoEntity.setCity(userWxInfo.getCountry()+"-"
					+userWxInfo.getProvince()+"-"
					+userWxInfo.getCity());
			wxInfoEntity.setAvatarUrl(userWxInfo.getHeadImgUrl());
			wxInfoEntity.setSex(userWxInfo.getSex());
			save(wxInfoEntity);
		} else {
			wxInfoEntity.setMpAppid(userWxInfo.getOpenId());

			wxInfoEntity.setNickName(userWxInfo.getNickname());
			wxInfoEntity.setCity(userWxInfo.getCountry()+"-"
					+userWxInfo.getProvince()+"-"
					+userWxInfo.getCity());
			wxInfoEntity.setAvatarUrl(userWxInfo.getHeadImgUrl());
			wxInfoEntity.setSex(userWxInfo.getSex());
			updateById(wxInfoEntity);
		}
	}

	@Override
	public void unbindMpAppid(String openId) {
		update(Wrappers.<WxInfo>lambdaUpdate()
				.set(WxInfo::getMpAppid, null)
				.eq(WxInfo::getMpAppid, openId));
	}

	@Override
	public WxInfo getInfoFromWpAppId(String openId) {
		WxInfo wxInfoEntity = getOne(Wrappers.<WxInfo>lambdaQuery()
				.eq(WxInfo::getMpAppid, openId));
		return wxInfoEntity;
	}

	//////////////////////////////////////////////////////////////////////////////WXMA
	@Override
	public R<?> waLoginByCode(String appid, String code) {
		if (StringUtils.isBlank(code)) {
			return R.failed("empty jscode");
		}
		final WxMaService wxService = WxMaConfiguration.getMaService(appid);
		try {
			WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
			if (session == null || StringUtils.isBlank(session.getOpenid())) {
				throw new CheckedException("微信授权失败");
			}
			log.info(session.getSessionKey());
			log.info(session.getOpenid());

			//TODO 可以增加自己的逻辑，关联业务相关数据
			//根据openid查询时候有用户信息
			WxInfo wxInfo = getOne(Wrappers.<WxInfo>lambdaQuery()
					.eq(WxInfo::getMaAppid, session.getOpenid())
					.or(a->a.eq(WxInfo::getWxUnionId, session.getUnionid())));
			if (wxInfo != null) {
				String uid = wxInfo.getUserId();
				String maAppid = wxInfo.getMaAppid();
				if (uid != null) {
					if (StringUtils.isEmpty(maAppid)) {
						wxInfo.setMaAppid(session.getOpenid());
						updateById(wxInfo);
					}
					User sysUserEntity = userService.getById(uid);
					if (sysUserEntity != null) {
						//已经绑定用户信息直接登录
//						return sysUserTokenService.createUserToken(sysUserEntity.getUserId(), LoginConstant.FROM_MA);
					}
				}
			}
			//没有绑定用户请前往绑定
			String sessionKey = session.getSessionKey();//UIDGenerator.orderId();
//            apiRedisUtils.set(sessionKey, session.getSessionKey() + ","
//                    + session.getOpenid() + ","
//                    + session.getUnionid(), 60 * 60);

			Map<String, Object> res = new HashMap<>();
			res.put("wxSessionKey", sessionKey);
			return R.ok(res);
		} catch (WxErrorException e) {
			log.error(e.getMessage(), e);
			throw new CheckedException("微信登录失败:" + e.getMessage());
		}
	}

	@Override
	public void bindMaAppid(String userId, WxMaUserInfo userInfo) {
		WxInfo wxInfoEntity = getOne(Wrappers.<WxInfo>lambdaQuery()
				.eq(WxInfo::getWxUnionId, userInfo.getUnionId()));
		if (wxInfoEntity == null) {
			wxInfoEntity = new WxInfo();
			wxInfoEntity.setUserId(userId);
			wxInfoEntity.setWxUnionId(userInfo.getUnionId());
			wxInfoEntity.setMaAppid(userInfo.getOpenId());

			wxInfoEntity.setNickName(userInfo.getNickName());
			wxInfoEntity.setCity(userInfo.getCountry()+"-"
					+userInfo.getProvince()+"-"
					+userInfo.getCity());
			wxInfoEntity.setAvatarUrl(userInfo.getAvatarUrl());
			try {
				wxInfoEntity.setSex(Integer.parseInt(userInfo.getGender()));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			save(wxInfoEntity);
		} else {
			wxInfoEntity.setUserId(userId);
			wxInfoEntity.setMaAppid(userInfo.getOpenId());

			wxInfoEntity.setNickName(userInfo.getNickName());
			wxInfoEntity.setCity(userInfo.getCountry()+"-"
					+userInfo.getProvince()+"-"
					+userInfo.getCity());
			wxInfoEntity.setAvatarUrl(userInfo.getAvatarUrl());
			try {
				wxInfoEntity.setSex(Integer.parseInt(userInfo.getGender()));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			updateById(wxInfoEntity);
		}
	}

	@Override
	public R<?> unbindMaAppid(String appid, Long userId, String code) {
		if (StringUtils.isBlank(code)) {
			return R.failed("empty jscode");
		}
		final WxMaService wxService = WxMaConfiguration.getMaService(appid);
		try {
			WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
			if (session == null || StringUtils.isBlank(session.getOpenid())) {
				throw new CheckedException("微信授权失败");
			}
			log.info(session.getSessionKey());
			log.info(session.getOpenid());

			List<WxInfo> wxinfos = list(Wrappers.<WxInfo>lambdaQuery()
					.eq(WxInfo::getUserId, userId)
					.eq(WxInfo::getMaAppid, session.getOpenid())
					.or(a->a.eq(WxInfo::getWxUnionId, session.getUnionid())));


			if (wxinfos != null) {
				wxinfos.forEach(wxinfo -> {
					wxinfo.setMaAppid(null);
					wxinfo.setUserId(null);
					updateById(wxinfo);
				});
			}
			return R.ok("解绑成功");
		} catch (WxErrorException e) {
			log.error(e.getMessage(), e);
			throw new CheckedException("微信Code解析失败:" + e.getMessage());
		}
	}
}
